<template>
  <div class="pull-refresh-wrapper">
    <!-- 下拉刷新提示 -->
    <div 
      class="pull-refresh" 
      :class="{ 'refreshing': isRefreshing }"
      :style="refreshStyle"
    >
      <div class="refresh-indicator">
        <el-icon v-if="isRefreshing"><Loading /></el-icon>
        <el-icon v-else><ArrowUp /></el-icon>
      </div>
      <span class="refresh-text">{{ refreshText }}</span>
    </div>
    
    <!-- 插槽内容 -->
    <div 
      class="pull-refresh-content" 
      ref="contentRef"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      @mousedown="handleMouseDown"
      @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
      @mouseleave="handleMouseUp"
    >
      <slot></slot>
    </div>
  </div>
</template>

<script>
import { ArrowUp, Loading } from '@element-plus/icons-vue'

export default {
  name: 'PullRefresh',
  components: {
    ArrowUp,
    Loading
  },
  props: {
    // 下拉刷新的最大距离
    maxPullDistance: {
      type: Number,
      default: 80
    },
    // 触发刷新的阈值比例
    refreshThreshold: {
      type: Number,
      default: 0.8
    },
    // 阻尼系数
    damping: {
      type: Number,
      default: 0.5
    }
  },
  emits: ['refresh'],
  data() {
    return {
      isRefreshing: false,
      isDragging: false,
      touchStartY: 0,
      touchMoveY: 0,
      mouseStartY: 0,
      mouseMoveY: 0,
      refreshDistance: 0,
      refreshText: '下拉刷新'
    }
  },
  computed: {
    refreshStyle() {
      return {
        transform: `translateY(${this.refreshDistance}px)`,
        height: `${this.refreshDistance > 0 ? this.refreshDistance : 0}px`,
        opacity: this.refreshDistance > 0 ? 1 : 0
      }
    }
  },
  methods: {
    // 触发刷新
    async triggerRefresh() {
      await this.performRefresh()
    },
    
    // 触摸事件处理
    handleTouchStart(event) {
      const content = this.$refs.contentRef
      if (content && content.scrollTop <= 1) {
        this.touchStartY = event.touches[0].clientY
      }
    },
    
    handleTouchMove(event) {
      if (this.isRefreshing || !this.touchStartY) return
      
      const content = this.$refs.contentRef
      if (content && content.scrollTop <= 1) {
        this.touchMoveY = event.touches[0].clientY
        const diff = this.touchMoveY - this.touchStartY
        
        if (diff > 0) {
          try {
            event.preventDefault()
          } catch (e) {
            console.warn('无法阻止默认滚动行为:', e)
          }
          
          this.refreshDistance = Math.min(diff * this.damping, this.maxPullDistance)
          
          if (this.refreshDistance >= this.maxPullDistance * this.refreshThreshold) {
            this.refreshText = '释放刷新'
          } else {
            this.refreshText = '下拉刷新'
          }
        }
      }
    },
    
    async handleTouchEnd() {
      if (this.isRefreshing) return
      
      if (this.refreshDistance >= this.maxPullDistance * this.refreshThreshold) {
        await this.performRefresh()
      } else {
        this.resetRefresh()
      }
      
      this.touchStartY = 0
    },
    
    // 鼠标事件处理
    handleMouseDown(event) {
      if (event.button !== 0) return
      
      const content = this.$refs.contentRef
      if (content && content.scrollTop <= 1) {
        this.isDragging = true
        this.mouseStartY = event.clientY
      }
    },
    
    handleMouseMove(event) {
      if (this.isRefreshing || !this.isDragging || !this.mouseStartY) return
      
      const content = this.$refs.contentRef
      if (content && content.scrollTop <= 1) {
        this.mouseMoveY = event.clientY
        const diff = this.mouseMoveY - this.mouseStartY
        
        if (diff > 0) {
          try {
            event.preventDefault()
          } catch (e) {
            console.warn('无法阻止默认鼠标移动行为:', e)
          }
          
          this.refreshDistance = Math.min(diff * this.damping, this.maxPullDistance)
          
          if (this.refreshDistance >= this.maxPullDistance * this.refreshThreshold) {
            this.refreshText = '释放刷新'
          } else {
            this.refreshText = '下拉刷新'
          }
        }
      }
    },
    
    async handleMouseUp() {
      if (this.isRefreshing || !this.isDragging) return
      
      if (this.refreshDistance >= this.maxPullDistance * this.refreshThreshold) {
        await this.performRefresh()
      } else {
        this.resetRefresh()
      }
      
      this.isDragging = false
      this.mouseStartY = 0
    },
    
    // 执行刷新
    async performRefresh() {
      this.isRefreshing = true
      this.refreshText = '正在刷新...'
      this.refreshDistance = this.maxPullDistance
      
      try {
        // 触发刷新事件
        await this.$emit('refresh')
        this.refreshText = '刷新成功'
        
        setTimeout(() => {
          this.resetRefresh()
        }, 1000)
      } catch (error) {
        this.refreshText = '刷新失败'
        console.error('刷新失败:', error)
        
        setTimeout(() => {
          this.resetRefresh()
        }, 1500)
      }
    },
    
    // 重置刷新状态
    resetRefresh() {
      this.refreshDistance = 0
      this.isRefreshing = false
      this.isDragging = false
      this.refreshText = '下拉刷新'
      this.touchStartY = 0
      this.mouseStartY = 0
    }
  }
}
</script>

<style scoped>
.pull-refresh-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.pull-refresh {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  background-color: transparent;
  overflow: hidden;
  z-index: 10;
  min-height: 40px;
}

.refresh-indicator {
  margin-right: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.refresh-text {
  color: #606266;
  font-size: 14px;
}

.refreshing .refresh-indicator .el-icon {
  animation: spin 1s linear infinite;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.pull-refresh-content {
  height: 100%;
  overflow-y: auto;
  user-select: none;
  -webkit-user-select: none;
  cursor: default;
}
</style>